package com.itheima.project.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.itheima.project.core.enums.search.SearchEnum;
import com.itheima.project.exception.ProjectException;
import com.itheima.project.vo.search.*;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 自定义ES参数转换委托类
 * @author mrchen
 * @date 2022/6/7 16:45
 */
public class DelegateEsParamParser {

    /**
     * 设置高亮参数
     * @param builder
     * @param paramVo
     */
    public  static void setHighlight(SearchSourceBuilder builder, RequestParamVo paramVo) {
        HighlightParam highlightParam = paramVo.getHighlightParam();
        if (highlightParam!=null){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field(highlightParam.getName());
            String preTag = highlightParam.getPreTag();
            String postTag = highlightParam.getPostTag();
            if (!StringUtils.isEmpty(preTag)) {
                highlightBuilder.preTags(highlightParam.getPreTag());
            }
            if (!StringUtils.isEmpty(postTag)) {
                highlightBuilder.postTags(highlightParam.getPostTag());
            }
            builder.highlighter(highlightBuilder);
        }
    }
    /**
     * 设置分页信息
     * @param builder
     * @param paramVo
     */
    public static void setPage(SearchSourceBuilder builder, RequestParamVo paramVo) {
        PageParam pageParam = paramVo.getPageParam();
        if (pageParam != null){
            builder.from(pageParam.getFrom());
            builder.size(pageParam.getSize());
        }
    }
    /**
     * 设置排序条件
     * @param builder
     * @param paramVo
     */
    public static void setSort(SearchSourceBuilder builder, RequestParamVo paramVo) {
        // 获取排序参数
        SortParam sortParam = paramVo.getSortParam();
        if(sortParam!=null){
            List<String> sortList = sortParam.getSort();
            List<String> nameList = sortParam.getName();
            for (int i = 0; i < nameList.size(); i++) {
                String sort = sortList.get(i);
                builder.sort(nameList.get(i),
                        SortParam.ASC.equals(sort)? SortOrder.ASC:SortOrder.DESC);
            }
        }
    }
    public static QueryBuilder getQueryBuilder(QueryParam queryParam) {
        if(queryParam==null || StringUtils.isEmpty(queryParam.getQueryType())){
            return null;
        }
        String queryType = queryParam.getQueryType();
        QueryBuilder queryBuilder = null;
        switch (queryType){
            case QueryParam.QUERY_TYPE_BOOL:
                queryBuilder = parseBoolQuery(queryParam);
                break;
            case QueryParam.QUERY_TYPE_MATCH:
                queryBuilder = parseMatchQuery(queryParam);
                break;
            case QueryParam.QUERY_TYPE_RANGE:
                queryBuilder = parseRangeQuery(queryParam);
                break;
            case QueryParam.QUERY_TYPE_TERM:
                queryBuilder = parseTermQuery(queryParam);
                break;
            default:
                throw new ProjectException(SearchEnum.DOCUMENT_SEARCH_FAIL);
        }
        return queryBuilder;
    }

    public static QueryBuilder parseTermQuery(QueryParam queryParam) {
        Optional<String> first = queryParam.getValue().stream().findFirst();
        if(first.isPresent()){
            return QueryBuilders.termQuery(queryParam.getName(),first.get());
        }
        return null;
    }

    /**
     * 封装原生范围条件
     * @param queryParam
     * @return
     */
    public static QueryBuilder parseRangeQuery(QueryParam queryParam) {
        RangeQueryBuilder rangeBuilder = QueryBuilders.rangeQuery(queryParam.getName());
        List<String> rangeType = queryParam.getRangeType();
        List<String> value = queryParam.getValue();
        int size = rangeType.size();
        for (int i = 0; i < size; i++) {
            String type = rangeType.get(i);
            switch (type){
                case "lt":
                    rangeBuilder.lt(value.get(i));
                    break;
                case "lte":
                    rangeBuilder.lte(value.get(i));
                    break;
                case "gt":
                    rangeBuilder.gt(value.get(i));
                    break;
                case "gte":
                    rangeBuilder.gte(value.get(i));
                    break;
                default:
            }
        }
        return rangeBuilder;
    }

    public static QueryBuilder parseMatchQuery(QueryParam queryParam) {
        Optional<String> first = queryParam.getValue().stream().findFirst();
        if(first.isPresent()){
            return QueryBuilders.matchQuery(queryParam.getName(),first.get());
        }
        return null;
    }

    public static QueryBuilder parseBoolQuery(QueryParam queryParam) {
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 查看must集合是否为空
        List<QueryParam> mustQuery = queryParam.getMustQuery();
        if (!CollectionUtils.isEmpty(mustQuery)){
            mustQuery.forEach(q -> {
                boolQuery.must(getQueryBuilder(q));
            });
        }
        // 查看should
        List<QueryParam> shouldQuery = queryParam.getShouldQuery();
        if (!CollectionUtils.isEmpty(shouldQuery)){
            mustQuery.forEach(q -> {
                boolQuery.should(getQueryBuilder(q));
            });
        }
        // 查看filter
        List<QueryParam> filterQuery = queryParam.getFilterQuery();
        if (!CollectionUtils.isEmpty(filterQuery)){
            mustQuery.forEach(q -> {
                boolQuery.filter(getQueryBuilder(q));
            });
        }
        // 查看must_not
        List<QueryParam> mustNotQuery = queryParam.getMustNotQuery();
        if (!CollectionUtils.isEmpty(mustNotQuery)){
            mustQuery.forEach(q -> {
                boolQuery.mustNot(getQueryBuilder(q));
            });
        }
        return boolQuery;
    }

    public static SearchSourceBuilder parseRequestParamVo(RequestParamVo paramVo){
        SearchSourceBuilder builder = new SearchSourceBuilder();
        QueryParam queryParam = paramVo.getQueryParam();
        // 设置query 查询条件
        QueryBuilder queryBuilder = getQueryBuilder(queryParam);
        if(queryBuilder!=null){
            builder.query(queryBuilder);
        }
        // 设置排序条件
        setSort(builder,paramVo);
        // 设置分页条件
        setPage(builder,paramVo);
        // 设置高亮条件
        setHighlight(builder,paramVo);
        // TODO 其它条件  未完待续
        return builder;
    }
    /**
     * 解析封装返回结果
     * @param response
     * @param paramVo
     * @return
     */
    public static SearchPageVo<Object> parseResponseResult(SearchResponse response, RequestParamVo paramVo) {
        SearchPageVo<Object> pageVo = new SearchPageVo<>();
        pageVo.setRecords(Lists.newArrayList());

        PageParam pageParam = paramVo.getPageParam();
        if(pageParam!=null){
            pageVo.setPage(pageParam.getPage());
            pageVo.setSize(pageParam.getSize());
        }

        SearchHits hits = response.getHits();
        long total = hits.getTotalHits().value;
        pageVo.setTotal(total);
        List<Object> list = Arrays.stream(hits.getHits())
                .map(SearchHit::getSourceAsString)
                .map(json -> JSON.parseObject(json,Object.class))
                .collect(Collectors.toList());
        pageVo.setRecords(list);
        return pageVo;
    }
    public static SearchSourceBuilder parseSearchSourceBuilder(NamedXContentRegistry namedXContentRegistry,String searchContent) throws IOException {
        XContentParser parser =
                XContentType.JSON.xContent().createParser(namedXContentRegistry,
                        LoggingDeprecationHandler.INSTANCE,
                        searchContent);
        return SearchSourceBuilder.fromXContent(parser);
    }
}
